/////////////////////////////////////////////////////////////////////////////
//
// Project ProjectForge Community Edition
// www.projectforge.org
//
// Copyright (C) 2001-2014 Kai Reinhard (k.reinhard@micromata.de)
//
// ProjectForge is dual-licensed.
//
// This community edition is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as published
// by the Free Software Foundation; version 3 of the License.
//
// This community edition is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
// Public License for more details.
//
// You should have received a copy of the GNU General Public License along
// with this program; if not, see http://www.gnu.org/licenses/.
//
/////////////////////////////////////////////////////////////////////////////
package org.projectforge.web.wicket;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Method;
import java.net.URLEncoder;
import java.util.Calendar;
import java.util.Date;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.wicket.AttributeModifier;
import org.apache.wicket.Component;
import org.apache.wicket.MarkupContainer;
import org.apache.wicket.Page;
import org.apache.wicket.behavior.AttributeAppender;
import org.apache.wicket.behavior.Behavior;
import org.apache.wicket.extensions.ajax.markup.html.AjaxEditableLabel;
import org.apache.wicket.markup.html.WebPage;
import org.apache.wicket.markup.html.basic.Label;
import org.apache.wicket.markup.html.form.DropDownChoice;
import org.apache.wicket.markup.html.form.FormComponent;
import org.apache.wicket.markup.html.form.TextField;
import org.apache.wicket.markup.html.image.ContextImage;
import org.apache.wicket.model.IModel;
import org.apache.wicket.model.Model;
import org.apache.wicket.protocol.http.RequestUtils;
import org.apache.wicket.request.Request;
import org.apache.wicket.request.Response;
import org.apache.wicket.request.Url;
import org.apache.wicket.request.UrlUtils;
import org.apache.wicket.request.cycle.RequestCycle;
import org.apache.wicket.request.mapper.parameter.PageParameters;
import org.apache.wicket.util.string.StringValue;
import org.projectforge.calendar.DayHolder;
import org.projectforge.calendar.TimePeriod;
import org.projectforge.common.BeanHelper;
import org.projectforge.common.ClassHelper;
import org.projectforge.common.DateFormatType;
import org.projectforge.common.DateFormats;
import org.projectforge.common.DateHelper;
import org.projectforge.common.DateHolder;
import org.projectforge.common.NumberHelper;
import org.projectforge.common.StringHelper;
import org.projectforge.core.BaseDao;
import org.projectforge.core.ConfigXml;
import org.projectforge.web.HtmlHelper;
import org.projectforge.web.LoginPage;
import org.projectforge.web.URLHelper;
import org.projectforge.web.WebConfig;
import org.projectforge.web.calendar.DateTimeFormatter;
import org.projectforge.web.fibu.ISelectCallerPage;
import org.projectforge.web.mobile.AbstractSecuredMobilePage;
import org.projectforge.web.mobile.MenuMobilePage;
import org.projectforge.web.wicket.components.DatePanel;
import org.projectforge.web.wicket.components.LabelValueChoiceRenderer;
import org.projectforge.web.wicket.flowlayout.ComponentWrapperPanel;
import org.projectforge.web.wicket.flowlayout.FieldsetPanel;
import org.projectforge.web.wicket.flowlayout.IconPanel;
import org.projectforge.web.wicket.flowlayout.IconType;
public class WicketUtils
{
private static final org.apache.log4j.Logger log = org.apache.log4j.Logger.getLogger(WicketUtils.class);
private static String APPLICATION_CONTEXT = "/ProjectForge";
private static String absoluteContextPath;
public static final String WICKET_APPLICATION_PATH = "wa/";
public static String getContextPath()
{
return APPLICATION_CONTEXT;
}
static void setContextPath(final String contextPath)
{
APPLICATION_CONTEXT = contextPath;
absoluteContextPath = null;
}
/**
* Examples: https://www.projectforge.org/demo or https://www.acme.com/ProjectForge.
* @return Absolute context path of the web application.
*/
public static String getAbsoluteContextPath()
{
if (absoluteContextPath == null) {
final RequestCycle requestCycle = RequestCycle.get();
final String url = requestCycle.getUrlRenderer().renderFullUrl(Url.parse(requestCycle.urlFor(LoginPage.class, null).toString()));
final String basePath = "/" + WICKET_APPLICATION_PATH;
final int pos = url.indexOf(basePath);
if (pos < 0) {
log.warn("Couln't get base url of '" + url + "'. Sub string '" + basePath + "' expected.");
return url;
}
absoluteContextPath = url.substring(0, pos);
}
return absoluteContextPath;
}
public static HttpServletRequest getHttpServletRequest(final Request request)
{
return (HttpServletRequest) request.getContainerRequest();
}
public static HttpServletResponse getHttpServletResponse(final Response response)
{
return (HttpServletResponse) response.getContainerResponse();
}
public static boolean contains(final PageParameters parameters, final String name)
{
final StringValue sval = parameters.get(name);
if (sval == null) {
return false;
} else {
return sval.isNull() == false;
}
}
public static String getAsString(final PageParameters parameters, final String name)
{
final StringValue sval = parameters.get(name);
if (sval == null || sval.isNull() == true) {
return null;
} else {
return sval.toString();
}
}
public static Integer getAsInteger(final PageParameters parameters, final String name)
{
final StringValue sval = parameters.get(name);
if (sval == null || sval.isNull() == true) {
return null;
} else {
return sval.toInteger();
}
}
public static int getAsInt(final PageParameters parameters, final String name, final int defaultValue)
{
final StringValue sval = parameters.get(name);
if (sval == null || sval.isNull() == true) {
return defaultValue;
} else {
return sval.toInt();
}
}
public static Long getAsLong(final PageParameters parameters, final String name)
{
final StringValue sval = parameters.get(name);
if (sval == null || sval.isNull() == true) {
return null;
} else {
return sval.toLong();
}
}
public static Boolean getAsBooleanObject(final PageParameters parameters, final String name)
{
final StringValue sval = parameters.get(name);
if (sval == null || sval.isNull() == true) {
return null;
} else {
return sval.toBooleanObject();
}
}
public static boolean getAsBoolean(final PageParameters parameters, final String name)
{
final StringValue sval = parameters.get(name);
if (sval == null || sval.isNull() == true) {
return false;
} else {
return sval.toBoolean();
}
}
public static Object getAsObject(final PageParameters parameters, final String name, final Class< ? > type)
{
final StringValue sval = parameters.get(name);
if (sval == null || sval.isNull() == true) {
return null;
} else {
return sval.to(type);
}
}
/**
* Renders <link type="image/x-icon" rel="shortcut icon" href="favicon.ico" />
* @param favicon The favicon file, e. g. "/ProjectForge/favicon.ico".
*/
public static String getCssForFavicon(final String favicon)
{
return "<link type=\"image/x-icon\" rel=\"shortcut icon\" href=\"" + favicon + "\" />";
}
/**
* Prepends APPLICATION_CONTEXT if url starts with '/', otherwise url is returned unchanged.
* @param url
*/
public static final String getAbsoluteUrl(final String url)
{
if (url.startsWith("/") == true) {
return APPLICATION_CONTEXT + url;
}
return url;
}
/**
* Get the url for the given path (without image path). Later, the path of the images is changeable.
* @param requestCycle Needed to encode url.
* @param subpath
* @return
*/
public static String getImageUrl(final RequestCycle requestCycle, final String path)
{
return getUrl(requestCycle, path, true);
}
/**
* Should be c:url equivalent, but isn't yet (works for now).
* @param requestCycle Needed to encode url.
* @param path
* @param encodeUrl
* @return path itself if not starts with '/' otherwise "/ProjectForge" + path with session id and params.
*/
public static String getUrl(final RequestCycle requestCycle, final String path, final boolean encodeUrl)
{
String url = UrlUtils.rewriteToContextRelative(path, requestCycle);
if (encodeUrl == true) {
url = requestCycle.getResponse().encodeURL(url);
}
return url;
}
/**
* Works for Wicket and non Wicket calling pages. For non Wicket callers the pageClass must be bookmarked in Wicket application.
* @param pageClass
* @param Optional list of params in tupel form: key, value, key, value...
*/
public static String getBookmarkablePageUrl(final Class< ? extends Page> pageClass, final String... params)
{
final RequestCycle requestCylce = RequestCycle.get();
if (requestCylce != null) {
final PageParameters pageParameter = getPageParameters(params);
return requestCylce.urlFor(pageClass, pageParameter).toString();
} else {
// RequestCycle.get().urlFor(pageClass, pageParameter).toString() can't be used for non wicket requests!
final String alias = WicketApplication.getBookmarkableMountPath(pageClass);
if (alias == null) {
log.error("Given page class is not mounted. Please mount class in WicketApplication: " + pageClass);
return getDefaultPageUrl();
}
if (params == null) {
return WICKET_APPLICATION_PATH + alias;
}
final StringBuffer buf = new StringBuffer();
buf.append(WICKET_APPLICATION_PATH).append(alias);
try {
for (int i = 0; i < params.length; i += 2) {
if (i == 0) {
buf.append("?");
} else {
buf.append("&");
}
buf.append(URLEncoder.encode(params[i], "UTF-8")).append("=");
if (i + 1 < params.length) {
buf.append(URLEncoder.encode(params[i + 1], "UTF-8"));
}
}
} catch (final UnsupportedEncodingException ex) {
log.error(ex.getMessage(), ex);
}
return buf.toString();
}
}
/**
* Tuples of parameters converted to Wicket parameters.
* @param params
* @return
*/
public static PageParameters getPageParameters(final String[] params)
{
final PageParameters pageParameters = new PageParameters();
if (params != null) {
for (int i = 0; i < params.length; i += 2) {
if (i + 1 < params.length) {
pageParameters.add(params[i], params[i + 1]);
} else {
pageParameters.add(params[i], null);
}
}
}
return pageParameters;
}
/**
* @param relativePagePath
* @return
* @see RequestUtils#toAbsolutePath(String, String)
* @see URLHelper#removeJSessionId(String)
*/
public final static String toAbsolutePath(final String requestUrl, final String relativePagePath)
{
final String absoluteUrl = RequestUtils.toAbsolutePath(requestUrl, relativePagePath);
return URLHelper.removeJSessionId(absoluteUrl);
}
/**
* @param id
* @return new PageParameters containing the given id as page parameter.
*/
public final static PageParameters getEditPageParameters(final Integer id)
{
return new PageParameters().set(AbstractEditPage.PARAMETER_KEY_ID, id);
}
/**
* @return Default page of ProjectForge. Currently {@link WicketApplication#DEFAULT_PAGE} is the default page (e. g. to redirect after
* login if no forward url is specified).
*/
public static String getDefaultPageUrl()
{
return getBookmarkablePageUrl(getDefaultPage());
}
/**
* @return Default page of ProjectForge. Currently {@link WicketApplication#DEFAULT_PAGE} is the default page (e. g. to redirect after
* cancel if no other return page is specified).
*/
public static Class< ? extends WebPage> getDefaultPage()
{
final WebConfig webConfig = ConfigXml.getInstance().getWebConfig();
return webConfig != null ? webConfig.getDefaultPage() : WicketApplication.DEFAULT_PAGE;
}
/**
* @return MenuMobilePage.class.
*/
public static Class< ? extends AbstractSecuredMobilePage> getDefaultMobilePage()
{
return MenuMobilePage.class;
}
/**
* If value is null or value is default value then nothing is done. Otherwise the given value is added as page parameter under the given
* key. Dates and TimePeriods are converted and can be gotten by {@link #getPageParameter(PageParameters, String, Class)}.
* @param pageParameters
* @param key
* @param value
* @see ClassHelper#isDefaultType(Class, Object)
*/
public static void putPageParameter(final PageParameters pageParameters, final String key, final Object value)
{
if (value == null) {
// Do not put null values to page parameters.
} else if (ClassHelper.isDefaultType(value.getClass(), value)) {
// Do not put default values to page parameters.
} else if (value instanceof Date) {
addOrReplaceParameter(pageParameters, key, ((Date) value).getTime());
} else if (value instanceof TimePeriod) {
addOrReplaceParameter(pageParameters, key, ((TimePeriod) value).getFromDate().getTime()
+ "-"
+ ((TimePeriod) value).getToDate().getTime());
} else {
addOrReplaceParameter(pageParameters, key, value);
}
}
public static void addOrReplaceParameter(final PageParameters pageParameters, final String key, final Object value)
{
if (pageParameters.get(key).isNull() == true) {
pageParameters.add(key, value);
} else {
pageParameters.set(key, value);
}
}
public static void putPageParameters(final ISelectCallerPage callerPage, final Object dataObject, final Object filterObject,
final PageParameters pageParameters, final String[] bookmarkableProperties)
{
if (bookmarkableProperties == null) {
return;
}
// final String pre = prefix != null ? prefix + "." : "";
for (final String propertyString : bookmarkableProperties) {
final InitialPageParameterHolder paramHolder = new InitialPageParameterHolder(propertyString);
final Object bean;
if (paramHolder.isFilterParameter() == true) {
bean = filterObject;
} else {
bean = dataObject;
}
try {
final Object value = BeanHelper.getProperty(bean, paramHolder.property);
WicketUtils.putPageParameter(pageParameters, paramHolder.prefix + paramHolder.alias, value);
} catch (final Exception ex) {
log.warn("Couldn't put page parameter '" + paramHolder.property + "' of bean '" + bean + "'. Ignoring this parameter.");
}
}
}
/**
* @param pageParameters
* @param key
* @param objectType
* @see #putPageParameter(PageParameters, String, Object)
*/
public static Object getPageParameter(final PageParameters pageParameters, final String key, final Class< ? > objectType)
{
if (objectType.isAssignableFrom(Date.class) == true) {
final StringValue sval = pageParameters.get(key);
if (sval.isNull() == true) {
return null;
}
return new Date(sval.toLongObject());
} else if (objectType.isAssignableFrom(Boolean.class) == true) {
return pageParameters.get(key).toBooleanObject();
} else if (objectType.isPrimitive() == true) {
if (Boolean.TYPE.equals(objectType)) {
return pageParameters.get(key).toBooleanObject();
} else if (Integer.TYPE.equals(objectType) == true) {
return pageParameters.get(key).toInteger();
} else if (Long.TYPE.equals(objectType) == true) {
return pageParameters.get(key).toLong();
} else if (Float.TYPE.equals(objectType) == true) {
return new Float(pageParameters.get(key).toDouble());
} else if (Double.TYPE.equals(objectType) == true) {
return pageParameters.get(key).toDouble();
} else if (Character.TYPE.equals(objectType) == true) {
return pageParameters.get(key).toChar();
} else {
log.warn("Primitive objectType '" + objectType + "' not yet implemented. Parameter type '" + key + "' is ignored.");
}
} else if (Enum.class.isAssignableFrom(objectType) == true) {
final StringValue sval = pageParameters.get(key);
if (sval.isNull() == true) {
return null;
}
final String sValue = sval.toString();
@SuppressWarnings({ "unchecked", "rawtypes"})
final Enum< ? > en = Enum.valueOf((Class<Enum>) objectType, sValue);
return en;
} else if (objectType.isAssignableFrom(Integer.class) == true) {
final StringValue sval = pageParameters.get(key);
if (sval.isNull() == true) {
return null;
}
return sval.toInteger();
} else if (objectType.isAssignableFrom(String.class) == true) {
return pageParameters.get(key).toString();
} else if (objectType.isAssignableFrom(TimePeriod.class) == true) {
final String sValue = pageParameters.get(key).toString();
if (sValue == null) {
return null;
}
final int pos = sValue.indexOf('-');
if (pos < 0) {
log.warn("PageParameter of type TimePeriod '" + objectType.getName() + "' in wrong format: " + sValue);
return null;
}
final Long fromTime = NumberHelper.parseLong(sValue.substring(0, pos));
final Long toTime = pos < sValue.length() - 1 ? NumberHelper.parseLong(sValue.substring(pos + 1)) : null;
return new TimePeriod(fromTime != null ? new Date(fromTime) : null, toTime != null ? new Date(toTime) : null);
} else {
log.error("PageParameter of type '" + objectType.getName() + "' not yet supported.");
}
return null;
}
public static boolean hasParameter(final PageParameters parameters, final String name)
{
final StringValue sval = parameters.get(name);
return sval != null && sval.isNull() == false;
}
/**
* At least one parameter should be given for setting the fill the bean with all book-markable properties (absent properties will be set
* to zero). If the given bean is an instance of {@link ISelectCallerPage} then the select/unselect methods are used, otherwise the
* properties will set directly of the given bean.
* @param bean
* @param parameters
* @param prefix
* @param bookmarkableProperties
*/
public static void evaluatePageParameters(final ISelectCallerPage callerPage, final Object dataObject, final Object filter,
final PageParameters parameters, final String[] bookmarkableProperties)
{
if (bookmarkableProperties == null) {
return;
}
// First check if any parameter is given:
boolean useParameters = false;
for (final String str : bookmarkableProperties) {
final InitialPageParameterHolder paramHolder = new InitialPageParameterHolder(str);
if (hasParameter(parameters, paramHolder.prefix + paramHolder.property) == true
|| hasParameter(parameters, paramHolder.prefix + paramHolder.alias) == true) {
useParameters = true;
break;
}
}
if (useParameters == false) {
// No book-markable parameters found.
return;
}
for (final String str : bookmarkableProperties) {
final InitialPageParameterHolder paramHolder = new InitialPageParameterHolder(str);
String key = null;
if (hasParameter(parameters, paramHolder.prefix + paramHolder.property) == true) {
key = paramHolder.property;
} else if (hasParameter(parameters, paramHolder.prefix + paramHolder.alias) == true) {
key = paramHolder.alias;
}
if (paramHolder.isCallerPageParameter() == true) {
if (callerPage == null) {
log.warn("PageParameter '" + str + "' ignored, ISelectCallerPage isn't given.");
} else if (key == null) {
callerPage.unselect(paramHolder.property);
} else {
callerPage.select(paramHolder.property, parameters.get(paramHolder.prefix + key).toString());
}
} else {
try {
final Object bean;
if (paramHolder.isFilterParameter() == true) {
// Use filter object
bean = filter;
if (bean == null) {
log.warn("PageParameter '" + str + "' ignored, filter isn't given.");
continue;
}
} else {
bean = dataObject;
if (bean == null) {
log.warn("PageParameter '" + str + "' ignored, dataObject isn't given.");
continue;
}
}
final Method method = BeanHelper.determineGetter(bean.getClass(), paramHolder.property);
if (key == null) {
BeanHelper.setProperty(bean, paramHolder.property, ClassHelper.getDefaultType(method.getReturnType()));
} else {
final Object value = WicketUtils.getPageParameter(parameters, paramHolder.prefix + key, method.getReturnType());
BeanHelper.setProperty(bean, paramHolder.property, value);
}
} catch (final Exception ex) {
log.warn("Property '" + key + "' not found. Ignoring URL parameter.");
}
}
}
}
/**
* Adds onclick attribute with "javascript:rowClick(this);".
* @param row Html tr element.
*/
public static void addRowClick(final Component row)
{
row.add(AttributeModifier.replace("onclick", "javascript:rowClick(this);"));
// add marker css class for contextMenu javaScript
row.add(new AttributeAppender("class", Model.of("withContextMenu"), " "));
}
/**
*
* @return
*/
public static ContextImage getInvisibleDummyImage(final String id, final RequestCycle requestCylce)
{
final ContextImage image = new ContextImage(id, WicketUtils.getImageUrl(requestCylce, WebConstants.IMAGE_SPACER));
image.setVisible(false);
return image;
}
public static Component getInvisibleComponent(final String id)
{
return new Label(id).setVisible(false);
}
/**
* @param label
* @param unit
* @return label [<unit>] (label with appended unit in brackets).
*/
public static String getLabelWithUnit(final String label, final String unit)
{
return label + " [" + unit + "]";
}
/**
* Uses "jiraSupportTooltipImage" as component id.
* @param parent only needed for localization
* @param id
* @return IconPanel which is invisible if JIRA isn't configured.
*/
public static IconPanel getJIRASupportTooltipIcon(final Component parent, final String id)
{
final IconPanel icon = new IconPanel(id, IconType.JIRA_SUPPORT, Model.of(parent.getString("tooltip.jiraSupport.field.title")),
Model.of(parent.getString("tooltip.jiraSupport.field.content")));
if (isJIRAConfigured() == false) {
icon.setVisible(false);
}
return icon;
}
/**
* Uses "jiraSupportTooltipImage" as component id. Please use {@link FieldsetPanel#addJIRASupportHelpIcon()} instead of this method if
* possible.
* @param fieldset needed for localization and for getting new child id.
* @return IconPanel which is invisible if JIRA isn't configured.
*/
public static IconPanel getJIRASupportTooltipIcon(final FieldsetPanel fieldset)
{
return getJIRASupportTooltipIcon(fieldset, fieldset.newIconChildId());
}
/**
*/
public static IconPanel getAlertTooltipIcon(final FieldsetPanel fieldset, final String tooltip)
{
return getAlertTooltipIcon(fieldset, null, Model.of(tooltip));
}
/**
*/
public static IconPanel getAlertTooltipIcon(final FieldsetPanel fieldset, final IModel<String> title, final IModel<String> tooltip)
{
final IconPanel icon = new IconPanel(fieldset.newIconChildId(), IconType.ALERT, title, tooltip);
return icon;
}
public static final boolean isJIRAConfigured()
{
return ConfigXml.getInstance().isJIRAConfigured();
}
/**
* Add JavaScript function showDeleteEntryQuestionDialog(). Depending on BaseDao.isHistorizable() a delete or mark-as-deleted question
* will be displayed. Usage in markup: <script wicket:id="showDeleteEntryQuestionDialog">[...]</script>
* @param parent
* @param dao
*/
public static void addShowDeleteRowQuestionDialog(final MarkupContainer parent, final BaseDao< ? > dao)
{
final StringBuffer buf = new StringBuffer();
buf.append("function showDeleteEntryQuestionDialog() {\n").append(" return window.confirm('");
if (dao.isHistorizable() == true) {
buf.append(parent.getString("question.markAsDeletedQuestion"));
} else {
buf.append(parent.getString("question.deleteQuestion"));
}
buf.append("');\n}\n");
parent.add(new Label("showDeleteEntryQuestionDialog", buf.toString()).setEscapeModelStrings(false).add(
AttributeModifier.replace("type", "text/javascript")));
}
/**
* Sets the html attribute placeholder.
* @param component
* @param value
*/
public static void setPlaceHolderAttribute(Component component, final String value)
{
if (component instanceof ComponentWrapperPanel) {
component = ((ComponentWrapperPanel) component).getFormComponent();
}
component.add(AttributeModifier.replace("placeholder", value));
}
/**
* @param parent Only for i18n needed.
* @param startTime Start time or null.
* @param stopTime Stop time or null.
* @return The weeks of year range for the given start an stop time.
*/
public static String getCalendarWeeks(final MarkupContainer parent, final Date startTime, final Date stopTime)
{
int fromWeek = -1;
int toWeek = -1;
if (startTime != null) {
fromWeek = DateHelper.getWeekOfYear(startTime);
}
if (stopTime != null) {
toWeek = DateHelper.getWeekOfYear(stopTime);
}
if (fromWeek < 0 && toWeek < 0) {
return "";
}
final StringBuffer buf = new StringBuffer();
buf.append(parent.getString("calendar.weekOfYearShortLabel")).append(" ");
if (fromWeek >= 0) {
buf.append(StringHelper.format2DigitNumber(fromWeek));
if (toWeek == -1) {
buf.append("-");
} else if (toWeek != fromWeek) {
buf.append("-").append(StringHelper.format2DigitNumber(toWeek));
}
} else {
buf.append("-").append(StringHelper.format2DigitNumber(toWeek));
}
return buf.toString();
}
/**
* @param date
*/
public static String getUTCDate(final Date date)
{
if (date == null) {
return "";
}
final DateHolder dh = new DateHolder(date);
return DateHelper.TECHNICAL_ISO_UTC.get().format(dh.getDate());
}
/**
* @param label Label as prefix
* @param date
* @return <label>: <date>
*/
public static String getUTCDate(final String label, final Date date)
{
if (date == null) {
return label + ":";
}
final DateHolder dh = new DateHolder(date);
return label + ": " + DateHelper.TECHNICAL_ISO_UTC.get().format(dh.getDate());
}
/**
* @param startTime Start time or null.
* @param stopTime Stop time or null.
*/
public static String getUTCDates(final Date startTime, final Date stopTime)
{
final StringBuffer buf = new StringBuffer();
final DateHolder start = startTime != null ? new DateHolder(startTime) : null;
final DateHolder stop = stopTime != null ? new DateHolder(stopTime) : null;
if (start != null) {
buf.append(DateHelper.TECHNICAL_ISO_UTC.get().format(start.getDate()));
if (stop != null) {
buf.append(" - ");
}
}
if (stop != null) {
buf.append(DateHelper.TECHNICAL_ISO_UTC.get().format(stop.getDate()));
}
return buf.toString();
}
public static LabelValueChoiceRenderer<Long> getDatumChoiceRenderer(final int lastNDays)
{
final LabelValueChoiceRenderer<Long> datumChoiceRenderer = new LabelValueChoiceRenderer<Long>();
for (int i = 0; i > -lastNDays; i--) {
final DayHolder day = new DayHolder();
day.add(Calendar.DAY_OF_YEAR, i);
datumChoiceRenderer.addValue(day.getSQLDate().getTime(),
DateTimeFormatter.instance().getFormattedDate(day.getSQLDate(), DateFormats.getFormatString(DateFormatType.DATE)));
}
return datumChoiceRenderer;
}
public static void append(final Component component, final RowCssClass... rowCssClasses)
{
for (final RowCssClass rowCssClass : rowCssClasses) {
component.add(AttributeModifier.append("class", rowCssClass.getCssClass()));
}
}
/**
* Adds a SimpleAttributeModifier("title", ...) to the given component.
* @param component
* @param title
* @param text
* @see #createTooltip(String, String)
* @see #setStyleHasTooltip(Component)
*/
public static Component addTooltip(final Component component, final String title, final String text)
{
return addTooltip(component, title, text, true);
}
/**
* Adds a SimpleAttributeModifier("title", ...) to the given component.
* @param component
* @param title
* @param text
* @see #createTooltip(String, String)
* @see #setStyleHasTooltip(Component)
*/
public static Component addTooltip(final Component component, final String title, final String text, final boolean rightAlignment)
{
return addTooltip(component, Model.of(title), Model.of(text), rightAlignment);
}
/**
* Adds a SimpleAttributeModifier("title", ...) to the given component.
* @param component
* @param text
* @see #createTooltip(String, String)
* @see #setStyleHasTooltip(Component)
*/
public static Component addTooltip(final Component component, final String text)
{
return addTooltip(component, text, true);
}
/**
* Adds a SimpleAttributeModifier("title", ...) to the given component.
* @param component
* @param text
* @param rightAlignment If false (default is true) the tooltip will be aligned at the bottom.
* @see #createTooltip(String, String)
* @see #setStyleHasTooltip(Component)
*/
public static Component addTooltip(final Component component, final String text, final boolean rightAlignment)
{
return addTooltip(component, null, Model.of(text), rightAlignment);
}
/**
* Adds a SimpleAttributeModifier("title", ...) to the given component. Does not modify the given tool tip text!
* @param component
* @param text
*/
public static Component addTooltip(final Component component, final IModel<String> text)
{
return addTooltip(component, text, true);
}
/**
* Adds a SimpleAttributeModifier("title", ...) to the given component. Does not modify the given tool tip text!
* @param component
* @param text
*/
public static Component addTooltip(final Component component, final IModel<String> text, final boolean rightAlignment)
{
return addTooltip(component, null, text, rightAlignment);
}
/**
* Adds a SimpleAttributeModifier("title", ...) to the given component. Does not modify the given tool tip text!
* @param component
* @param title
* @param text If the string contains "\n" characters then html=true and <br/> are used.
*/
public static Component addTooltip(final Component component, final IModel<String> title, final IModel<String> text)
{
return addTooltip(component, title, text, true);
}
/**
* Adds a SimpleAttributeModifier("title", ...) to the given component. Does not modify the given tool tip text!
* @param component
* @param title
* @param text If the string contains "\n" characters then html=true and <br/> are used.
* @param rightAlignment If false (default is true) the tooltip will be aligned at the bottom.
*/
public static Component addTooltip(final Component component, final IModel<String> title, final IModel<String> text,
final boolean rightAlignment)
{
@SuppressWarnings("serial")
final IModel<String> myModel = new Model<String>() {
/**
* @see org.apache.wicket.model.Model#getObject()
*/
@Override
public String getObject()
{
if (text != null && text.getObject() != null && text.getObject().indexOf("\n") > 0) {
final String newText = HtmlHelper.escapeHtml(text.getObject(), true);
return newText;
}
return text.getObject();
}
};
component.add(AttributeModifier.replace("data-html", true));
if (title != null && title.getObject() != null) {
component.add(AttributeModifier.replace("rel", rightAlignment ? "mypopup-right" : "mypopup"));
component.add(AttributeModifier.replace("data-original-title", title));
component.add(AttributeModifier.replace("data-content", myModel));
} else {
component.add(AttributeModifier.replace("rel", rightAlignment ? "mytooltip-right" : "mytooltip"));
component.add(AttributeModifier.replace("title", myModel));
}
return component;
}
/**
* You need to use {@link AjaxEditableLabel#getLabel()}.
* @param label
* @return
*/
public static Component addEditableLabelDefaultTooltip(final Component label)
{
return addTooltip(label, label.getString("form.ajaxEditableLabel.tooltip"));
}
public static Component setWarningTooltip(final Component component)
{
component.add(AttributeModifier.append("class", "warning"));
return component;
}
/**
* Sets readonly="readonly" and "readOnly" as class.
* @param component
* @return This for chaining.
*/
public static FormComponent< ? > setReadonly(final FormComponent< ? > component)
{
component.add(AttributeModifier.append("class", "readonly"));
component.add(AttributeModifier.replace("readonly", "readonly"));
return component;
}
/**
* Sets attribute size (only for TextFields) and style="length: width"; The width value is size + 0.5 em and for drop down choices size +
* 2em;
* @param component
* @param size
* @return This for chaining.
*/
public static FormComponent< ? > setSize(final FormComponent< ? > component, final int size)
{
return setSize(component, size, true);
}
/**
* Sets attribute size (only for TextFields) and style="length: width"; The width value is size + 0.5 em and for drop down choices size +
* 2em;
* @param component
* @param size
* @param important If true then "!important" is appended to the width style (true is default).
* @return This for chaining.
*/
public static FormComponent< ? > setSize(final FormComponent< ? > component, final int size, final boolean important)
{
if (component instanceof TextField) {
component.add(AttributeModifier.replace("size", String.valueOf(size)));
}
final StringBuffer buf = new StringBuffer(20);
buf.append("width: ");
if (component instanceof DropDownChoice) {
buf.append(size + 2).append("em");
} else {
buf.append(size).append(".5em");
}
if (important == true) {
buf.append(" !important;");
}
buf.append(";");
component.add(AttributeModifier.append("style", buf.toString()));
return component;
}
/**
* Sets attribute size (only for TextFields) and style="width: x%";
* @param component
* @param size
* @return This for chaining.
*/
public static FormComponent< ? > setPercentSize(final FormComponent< ? > component, final int size)
{
component.add(AttributeModifier.append("style", "width: " + size + "%;"));
return component;
}
/**
* Sets attribute font-size: style="font-size: 1.1em;";
* @param component
* @param size
* @return This for chaining.
*/
public static Component setFontSizeLarge(final Component component)
{
component.add(AttributeModifier.append("style", "font-size: 1.5em;"));
return component;
}
public static Component setStrong(final Component component)
{
component.add(AttributeModifier.append("style", "font-weight: bold;"));
return component;
}
/**
* Sets attribute style="height: <height>ex;"
* @param component
* @param size
* @return This for chaining.
*/
public static FormComponent< ? > setHeight(final FormComponent< ? > component, final int height)
{
component.add(AttributeModifier.append("style", "height: " + height + "ex;"));
return component;
}
/**
* Adds class="focus" to the given component. It's evaluated by the adminica_ui.js. FocusOnLoadBehaviour doesn't work because the focus is
* set to early (before the components are visible).
* @param component
* @return This for chaining.
*/
public static FormComponent< ? > setFocus(final FormComponent< ? > component)
{
component.add(setFocus());
return component;
}
/**
* Same as {@link #setFocus(FormComponent)}
* @return AttributeAppender
*/
public static Behavior setFocus()
{
return new FocusOnLoadBehavior();
}
/**
* For field-sets with multiple fields this method generates a multi label, such as "label1/label2", e. g. "zip code/city".
* @param label
* @return
*/
public static String createMultipleFieldsetLabel(final String... labels)
{
return StringHelper.listToString("/", labels);
}
/**
* If true then a tick-mark icon is returned, otherwise an invisible label.
* @param requestCycle
* @param componentId
* @param value
* @return
*/
public static Component createBooleanLabel(final RequestCycle requestCycle, final String componentId, final boolean value)
{
if (value == true) {
return new IconPanel(componentId, IconType.ACCEPT);
}
return new Label(componentId, "invisible").setVisible(false);
}
/**
* Searchs the attribute behavior (SimpleAttributeModifier or AttibuteApendModifier) with the given attribute name and returns it if
* found, otherwise null.
* @param comp
* @param name Name of attribute.
*/
public static AttributeModifier getAttributeModifier(final Component comp, final String name)
{
for (final Behavior behavior : comp.getBehaviors()) {
if (behavior instanceof AttributeAppender && name.equals(((AttributeAppender) behavior).getAttribute()) == true) {
return (AttributeAppender) behavior;
} else if (behavior instanceof AttributeModifier && name.equals(((AttributeModifier) behavior).getAttribute()) == true) {
return (AttributeModifier) behavior;
}
}
return null;
}
/**
* Calls {@link Component#setResponsePage(Page)}. If the responseItem is an instance of a Page then setResponse for this Page is called
* otherwise setResponse is called via {@link Component#getPage()}.
* @param component
* @param responseItem Page or Component.
*/
public static void setResponsePage(final Component component, final Component responseItem)
{
if (responseItem instanceof Page) {
component.setResponsePage((Page) responseItem);
} else {
component.setResponsePage(responseItem.getPage());
}
}
/**
* Casts callerPage to Component and calls {@link #setResponsePage(Component, Component)}.
* @param component
* @param callerPage Must be an instance of Component (otherwise a ClassCastException is thrown).
*/
public static void setResponsePage(final Component component, final ISelectCallerPage callerPage)
{
setResponsePage(component, (Component) callerPage);
}
public static AttributeModifier javaScriptConfirmDialogOnClick(final String message)
{
final String escapedText = message.replace("'", "\'");
return AttributeModifier.replace("onclick", "javascript:return showConfirmDialog('" + escapedText + "');");
}
@SuppressWarnings("unchecked")
public static void setLabel(final FormComponent< ? > component, final Label label)
{
final IModel<String> labelModel = (IModel<String>) label.getDefaultModel();
if (component instanceof DatePanel) {
((DatePanel) component).getDateField().setLabel(labelModel);
} else {
component.setLabel(labelModel);
}
}
public static boolean isParent(final Component parent, final Component descendant)
{
final MarkupContainer p = descendant.getParent();
if (p == null) {
return false;
} else if (p == parent) {
return true;
} else {
return isParent(parent, p);
}
}
}